//
//  CubeDemoDrawer.hpp
//  demo
//
//  Created by vonchenchen on 2021/3/18.
//  Copyright © 2021 vonchenchen. All rights reserved.
//

#ifndef CubeDemoDrawer_hpp
#define CubeDemoDrawer_hpp

#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <cmath>
#include <algorithm>
#include <ToyRenderer.h>
#include <ToyBmp.h>
#include <ToyTexture.h>
#include "BaseModle.h"

using namespace ToyCube;

class ToyObj{
public:
    ToyObj(){
        _model_mat.SetIdentify();
    }
    virtual ~ToyObj(){}
    
    virtual void SetRotateCube(float x, float y ,float z ,float angle){
        float arc = angle * PI / 180;
        _rotate_mat = ToyCube::RotateMat(x, y, z, arc);
    }
    
    virtual void SetTransCube(float x, float y ,float z){
        _trans_mat = ToyCube::TranslateMat(x, y, z);
    }
    
    virtual void SetScaleCube(float x, float y, float z){
        _scale_mat = ToyCube::SacleMat(x, y, z);
    }
    
    virtual void Draw(ToyRenderer &renderer, ToyTexture **shader_texture,
    Mat<4, 4, float> *_mvp_mat, VertexAttrib shader_vertexAttrib[]) = 0;
    
    Mat<4, 4, float> _rotate_mat;
    Mat<4, 4, float> _trans_mat;
    Mat<4, 4, float> _scale_mat;
    Mat<4, 4, float> _model_mat;
};

class Cube : public ToyObj{
public:
    
    const static int SIDE_FRONT = 0;
    const static int SIDE_BACK = 1;
    const static int SIDE_LEFT = 2;
    const static int SIDE_RIGHT = 3;
    const static int SIDE_TOP = 4;
    const static int SIDE_BOTTON = 5;
    
    Cube(){
        LoadBaseCube(&_mesh);
        memset(texs, 0, 6 * sizeof(ToyTexture *));
    }
    virtual ~Cube(){
        ReleaseBaseCube(_mesh);
    }
    
    virtual void Draw(ToyRenderer &renderer, ToyTexture **shader_texture,
                    Mat<4, 4, float> *_mvp_mat, VertexAttrib shader_vertexAttrib[]){
        
        //保存全局texture
        ToyTexture *rec = *shader_texture;
        
        for(int i=0; i<12; i+=2){
            
            int tex_idx = i/2;
            if(texs[tex_idx]){
                //更新当前渲染texture
                *shader_texture = texs[tex_idx];
            }
            
            //根据索引拿到当前三角形的顶点坐标
            shader_vertexAttrib[0] = _mesh[CUBE_VERTEX_INDEX[i][0]];
            shader_vertexAttrib[1] = _mesh[CUBE_VERTEX_INDEX[i][1]];
            shader_vertexAttrib[2] = _mesh[CUBE_VERTEX_INDEX[i][2]];
            //给当前三角形顶点分配纹理坐标
            shader_vertexAttrib[0].uv = {1, 0};
            shader_vertexAttrib[1].uv = {0, 0};
            shader_vertexAttrib[2].uv = {0, 1};
            renderer.Draw();

            shader_vertexAttrib[0] = _mesh[CUBE_VERTEX_INDEX[i+1][0]];
            shader_vertexAttrib[1] = _mesh[CUBE_VERTEX_INDEX[i+1][1]];
            shader_vertexAttrib[2] = _mesh[CUBE_VERTEX_INDEX[i+1][2]];
            shader_vertexAttrib[0].uv = {0, 1};
            shader_vertexAttrib[1].uv = {1, 1};
            shader_vertexAttrib[2].uv = {1, 0};
            renderer.Draw();
            
            //绘制完先更新为保存的texture
            *shader_texture = rec;
        }
        
        memset(texs, 0, 6*sizeof(ToyTexture *));
    }
    
    void SetColor(int side, ToyTexture *tex){
        texs[side] = tex;
    }
    
protected:
    VertexAttrib *_mesh;
    ToyTexture *texs[6];
};

class CubeDrawer{
  
public:
    CubeDrawer();
    virtual ~CubeDrawer();
    
    void Init(int width, int height);
    //void SetRotateCube(float x, float y ,float z ,float angle);
    //void SetTransCube(float x, float y ,float z);
    //void SetScaleCube(float x, float y, float z);
    void SetCameraPos(const Vec<3, float>& up, const Vec<3, float>& eye, const Vec<3, float>& at);
    void SetPersPro(float fovy, float aspect, float near, float far);
    void RequestRender(const char *path);
    
    Bitmap *GetFrameBuffer(){
        return renderer.GetFrameBuffer();
    }
    
    inline void SetLightEnable(bool enable){
        _enable_light = enable;
    }
    
    inline bool GetLightEnable(){
        return _enable_light;
    }
    
    inline void SetAntiAliasing(bool enable){
        renderer.SetAntiAliasingEnable(enable);
    }
    
    inline bool GetAntiAliasing(){
        return renderer.GetAntiAliasingEnable();
    }
    
protected:
    void CalculateModelMat();
    void LoadTextures();
    
protected:
    ToyRenderer renderer;
    Mat<4, 4, float> _rotate_mat;
    Mat<4, 4, float> _trans_mat;
    Mat<4, 4, float> _scale_mat;
    Mat<4, 4, float> _model_mat;
    Mat<4, 4, float> _camera_mat;
    Mat<4, 4, float> _pers_proj_mat;
    Mat<4, 4, float> _mvp_mat;
    
    Vec<3, float> _eye_pos;
    
    //当前渲染的顶点
    VertexAttrib _shader_vertexAttrib[3];
    //当前渲染的纹理
    ToyTexture *_shader_texture;
    int tri_index;
    
    const int VARYING_TEXUV = 0;
    const int VARYING_NORMAL = 1;
    const int VARYING_COORDS = 2;
    
    std::unique_ptr<ToyTexture> _texture_0;
    std::unique_ptr<ToyTexture> _texture_1;
    std::unique_ptr<ToyTexture> _texture_2;
    
    std::unique_ptr<ToyTexture> _texture_rabbit;
    
    Cube _cube;
    
    Light _light_1;
    
    bool _enable_light{false};
    bool inited{false};
};

#endif /* CubeDemoDrawer_hpp */
